# -*- coding: utf-8 -*-
"""
认证API路由

提供用户认证相关的API接口：
- 用户登录
- 令牌刷新
- 用户登出
- 密码修改
"""

from datetime import timedelta
from typing import Dict, Any, Optional
from fastapi import APIRouter, Depends, HTTPException, status, Request
from fastapi.security import HTTPBearer
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field
import logging
import uuid

from ...auth.jwt_auth import (
    jwt_manager,
    password_manager,
    get_current_user,
    get_current_active_user
)
from ...core.exceptions import AuthenticationError, ValidationError
from ...core.dto import ResponseDTO
from ...core.database import get_db
from ...models.rbac import User
from ...services.captcha_service import get_captcha_service
from ...services.user_service import get_user_service

logger = logging.getLogger(__name__)
router = APIRouter()


class LoginRequest(BaseModel):
    """登录请求"""
    username: str = Field(..., description="用户名")
    password: str = Field(..., description="密码")
    captcha_code: Optional[str] = Field(None, description="验证码")
    session_id: Optional[str] = Field(None, description="会话ID")


class LoginResponse(BaseModel):
    """登录响应"""
    access_token: str = Field(..., description="访问令牌")
    refresh_token: str = Field(..., description="刷新令牌")
    token_type: str = Field(default="bearer", description="令牌类型")
    expires_in: int = Field(..., description="令牌有效期（秒）")
    user_info: Dict[str, Any] = Field(..., description="用户信息")


class RefreshTokenRequest(BaseModel):
    """刷新令牌请求"""
    refresh_token: str = Field(..., description="刷新令牌")


class ChangePasswordRequest(BaseModel):
    """修改密码请求"""
    current_password: str = Field(..., description="当前密码")
    new_password: str = Field(..., description="新密码")


@router.post("/login", response_model=ResponseDTO[Dict[str, Any]], summary="用户登录")
async def login(request: LoginRequest, client_request: Request, db=Depends(get_db)):
    """
    用户登录
    
    验证用户凭据并返回JWT令牌，支持验证码防暴力破解
    """
    try:
        captcha_svc = get_captcha_service()
        user_svc = get_user_service(db)

        # 1. 验证验证码（始终必需）
        if not request.captcha_code or not request.session_id:
            raise AuthenticationError("需要验证码")

        # 验证验证码
        if not captcha_svc.verify_captcha(request.session_id, request.captcha_code):
            # 验证码错误，增加失败计数
            captcha_svc.increment_login_fails(request.username)
            raise AuthenticationError("验证码错误")

        # 2. 从数据库验证用户名密码
        try:
            user = await user_svc.authenticate_user(request.username, request.password)
            if not user:
                # 用户名或密码错误，增加失败计数
                captcha_svc.increment_login_fails(request.username)
                raise AuthenticationError("用户名或密码错误")
        except AuthenticationError:
            # 重新抛出认证错误（如账户锁定等）
            captcha_svc.increment_login_fails(request.username)
            raise

        # 3. 获取用户详细信息
        user_info = await user_svc.get_user_info(user.id)
        if not user_info:
            raise AuthenticationError("获取用户信息失败")

        # 4. 更新登录信息
        client_ip = client_request.client.host if client_request.client else None
        await user_svc.update_login_info(user.id, client_ip)

        # 5. 登录成功，重置失败计数
        captcha_svc.reset_login_fails(request.username)

        # 6. 生成令牌
        token_data = {
            "sub": str(user.id),
            "username": user.username,
            "permissions": user_info["permissions"]
        }

        access_token = jwt_manager.create_access_token(token_data)
        refresh_token = jwt_manager.create_refresh_token(token_data)

        # 7. 构造响应
        login_response = LoginResponse(
            access_token=access_token,
            refresh_token=refresh_token,
            expires_in=jwt_manager.access_token_expire_minutes * 60,
            user_info={
                "user_id": user.id,
                "username": user.username,
                "real_name": user_info["real_name"],
                "email": user.email,
                "department": user_info["department"],
                "position": user_info["position"],
                "permissions": user_info["permissions"]
            }
        )

        logger.info(f"用户登录成功: {request.username} (ID: {user.id})")

        return ResponseDTO[Dict[str, Any]](
            success=True,
            message="登录成功",
            data=login_response.dict()
        )

    except AuthenticationError as e:
        logger.warning(f"登录失败: {request.username} - {e.message}")

        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=e.message
        )
    except Exception as e:
        logger.error(f"登录异常: {e}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="登录服务异常"
        )


@router.post("/refresh", response_model=ResponseDTO[Dict[str, Any]], summary="刷新令牌")
async def refresh_token(request: RefreshTokenRequest):
    """
    刷新访问令牌
    
    使用刷新令牌获取新的访问令牌
    """
    try:
        # 刷新访问令牌
        new_access_token = jwt_manager.refresh_access_token(request.refresh_token)

        response_data = {
            "access_token": new_access_token,
            "token_type": "bearer",
            "expires_in": jwt_manager.access_token_expire_minutes * 60
        }

        return ResponseDTO[Dict[str, Any]](
            success=True,
            message="令牌刷新成功",
            data=response_data
        )

    except AuthenticationError as e:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=e.message
        )
    except Exception as e:
        logger.error(f"令牌刷新异常: {e}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="令牌刷新服务异常"
        )


@router.post("/logout", response_model=ResponseDTO[Dict[str, str]], summary="用户登出")
async def logout(current_user: Dict[str, Any] = Depends(get_current_active_user)):
    """
    用户登出
    
    注销当前用户会话（实际实现中可以将令牌加入黑名单）
    """
    try:
        # TODO: 实际实现中可以将令牌加入Redis黑名单

        logger.info(f"用户登出: {current_user.get('username')}")

        return ResponseDTO[Dict[str, str]](
            success=True,
            message="登出成功",
            data={"message": "您已安全登出"}
        )

    except Exception as e:
        logger.error(f"登出异常: {e}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="登出服务异常"
        )


@router.get("/me", response_model=ResponseDTO[Dict[str, Any]], summary="获取当前用户信息")
async def get_current_user_info(
        current_user: Dict[str, Any] = Depends(get_current_active_user),
        db=Depends(get_db)
):
    """
    获取当前登录用户的详细信息
    """
    try:
        user_svc = get_user_service(db)

        # 从数据库获取完整的用户信息
        user_info = await user_svc.get_user_info(current_user.get("user_id"))
        if not user_info:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="用户信息不存在"
            )

        # 添加令牌信息
        user_info["token_expires"] = current_user.get("exp")

        return ResponseDTO[Dict[str, Any]](
            success=True,
            message="获取用户信息成功",
            data=user_info
        )

    except Exception as e:
        logger.error(f"获取用户信息异常: {e}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="获取用户信息失败"
        )


@router.post("/change-password", response_model=ResponseDTO[Dict[str, str]], summary="修改密码")
async def change_password(
        request: ChangePasswordRequest,
        current_user: Dict[str, Any] = Depends(get_current_active_user),
        db=Depends(get_db)
):
    """
    修改当前用户密码
    """
    try:
        user_svc = get_user_service(db)

        # 从数据库修改密码（包含密码验证逻辑）
        await user_svc.change_password(
            current_user.get("user_id"),
            request.current_password,
            request.new_password
        )

        logger.info(f"用户修改密码: {current_user.get('username')} (ID: {current_user.get('user_id')})")

        return ResponseDTO[Dict[str, str]](
            success=True,
            message="密码修改成功",
            data={"message": "密码已成功修改，请重新登录"}
        )

    except (AuthenticationError, ValidationError) as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=e.message
        )
    except Exception as e:
        logger.error(f"修改密码异常: {e}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="修改密码失败"
        )


# ==================== 验证码相关接口 ====================

class CaptchaRequest(BaseModel):
    """验证码请求"""
    pass  # 不需要任何参数


class CaptchaResponse(BaseModel):
    """验证码响应"""
    session_id: str = Field(..., description="会话ID")
    captcha_image: str = Field(..., description="验证码图片(Base64)")


class VerifyCaptchaRequest(BaseModel):
    """验证验证码请求"""
    session_id: str = Field(..., description="会话ID")
    captcha_code: str = Field(..., description="验证码")


@router.post("/captcha", response_model=ResponseDTO[CaptchaResponse], summary="获取验证码")
async def get_captcha():
    """
    获取验证码
    
    直接生成并返回验证码，不需要任何参数
    """
    try:
        captcha_svc = get_captcha_service()

        # 生成会话ID
        session_id = str(uuid.uuid4())

        # 生成验证码
        base64_image, _ = captcha_svc.generate_captcha(session_id)

        response_data = CaptchaResponse(
            session_id=session_id,
            captcha_image=base64_image
        )

        return ResponseDTO[CaptchaResponse](
            success=True,
            message="验证码获取成功",
            data=response_data
        )

    except Exception as e:
        logger.error(f"获取验证码异常: {e}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="验证码服务异常"
        )


@router.post("/verify-captcha", response_model=ResponseDTO[Dict[str, bool]], summary="验证验证码")
async def verify_captcha(request: VerifyCaptchaRequest):
    """
    验证验证码
    
    验证用户输入的验证码是否正确
    """
    try:
        captcha_svc = get_captcha_service()

        # 验证验证码
        is_valid = captcha_svc.verify_captcha(request.session_id, request.captcha_code)

        return ResponseDTO[Dict[str, bool]](
            success=True,
            message="验证码验证成功" if is_valid else "验证码错误",
            data={"valid": is_valid}
        )

    except Exception as e:
        logger.error(f"验证验证码异常: {e}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="验证码验证服务异常"
        )


@router.post("/clear-cache", response_model=ResponseDTO[Dict[str, str]], summary="清除缓存(临时调试接口)")
async def clear_cache():
    """
    清除缓存 - 临时调试接口
    
    清除Redis和内存中的登录失败计数缓存
    """
    try:
        from ...core.redis_client import get_redis

        redis_client = get_redis()
        redis_client.clear_memory_cache()

        return ResponseDTO[Dict[str, str]](
            success=True,
            message="缓存清除成功",
            data={"message": "所有登录失败记录已清除"}
        )

    except Exception as e:
        logger.error(f"清除缓存异常: {e}", exc_info=True)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail="清除缓存失败"
        )
